package org.origin.centre.filter;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.origin.centre.model.exception.XException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

/**
 * Exception 全局异常拦截器,只是拦截异常
 *
 * @author ferret
 * @version 2024-05-08
 */
@SuppressWarnings("unused")
public class HandlerFilterException extends ExceptionHandlerExceptionResolver {
    private final Logger logger = LoggerFactory.getLogger(HandlerFilterException.class);
    private final boolean isResultOk;

    public HandlerFilterException(boolean isResultOk) {
        this.isResultOk = isResultOk;
    }

    @Override
    @SuppressWarnings("NullableProblems")
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
        HttpStatus status = this.getStatus(exception);
        String message = this.getMessage(exception);
        this.printLog(status, message, request, response, handler, exception);
        if (isResponseJson(request, response, (HandlerMethod) handler)) {
            return responseJson(status, message);
        } else {
            return responseView(status, message);
        }
    }

    /**
     * 错误响应
     *
     * @param message 异常信息
     * @return ModelAndView
     */
    protected ModelAndView responseJson(HttpStatus status, String message) {
        ModelAndView mv = new ModelAndView();
        mv.setView(new MappingJackson2JsonView());
        mv.setStatus(this.isResultOk ? HttpStatus.OK : status);
        mv.addObject("status", status.value());
        mv.addObject("message", message);
        return mv;
    }

    /**
     * 错误响应
     *
     * @param message 异常信息
     * @return ModelAndView
     */
    protected ModelAndView responseView(HttpStatus status, String message) {
        ModelAndView mv = new ModelAndView();
        mv.setStatus(this.isResultOk ? HttpStatus.OK : status);
        mv.addObject("status", status.value());
        mv.addObject("message", message.replaceAll("\n", "<br/>"));
        return mv;
    }

    /**
     * 获取到错误码
     *
     * @param exception 异常信息
     * @return 错误错误码
     */
    protected HttpStatus getStatus(Exception exception) {
        if (exception instanceof AuthenticationException) {
            // token exception
            return HttpStatus.UNAUTHORIZED;
        } else {
            // other exception
            return HttpStatus.BAD_REQUEST;
        }
    }

    /**
     * 获取到错误信息
     *
     * @param exception 异常信息
     * @return 错误信息
     */
    protected String getMessage(Exception exception) {
        String message;
        if (exception instanceof InvalidBearerTokenException) {
            message = "访问失败，凭证已过期";
        } else if (exception instanceof BadCredentialsException) {
            // credentials exception
            message = "认证失败，密码输入错误";
        } else if (exception instanceof LockedException) {
            // account status exception
            message = "认证失败，用户已被锁定";
        } else if (exception instanceof AccountExpiredException) {
            // account status exception
            message = "认证失败，用户账户已过期";
        } else if (exception instanceof DisabledException) {
            // account status exception
            message = "认证失败，用户已不可用";
        } else if (exception instanceof AccountStatusException) {
            // account status exception
            message = "认证失败，用户已被锁定";
        } else if (exception instanceof AuthenticationException) {
            // security exception
            message = "认证失败，" + exception.getMessage();
        }
//        } else if (exception instanceof InvalidGrantException) {
//            // security exception
//            message = "认证失败，" + exception.getMessage();
//        }
        else if (exception instanceof AccessDeniedException) {
            // security exception
            message = "您没有访问权限，请联系管理员";
        } else if (exception instanceof MethodArgumentNotValidException) {
            // argument exception
            FieldError fieldError = ((MethodArgumentNotValidException) exception).getBindingResult().getFieldError();
            message = fieldError != null ? "参数错误，" + fieldError.getDefaultMessage() : "未知参数错误";
        } else if (exception instanceof BindException) {
            // argument exception
            FieldError fieldError = ((BindException) exception).getBindingResult().getFieldError();
            message = fieldError != null ? "参数错误，" + fieldError.getDefaultMessage() : "未知参数错误";
        } else if (exception instanceof IllegalArgumentException) {
            // public exception
            message = exception.getLocalizedMessage();
        } else if (exception instanceof XException) {
            // myself exception
            message = exception.getLocalizedMessage();
        } else {
            // common exception
            message = "系统错误，请联系管理员！" + exception.getLocalizedMessage();
        }
        return message;
    }

    /**
     * 判断请求是否是JSON格式
     *
     * @param response      HttpServletResponse，用于检查响应的Content-Type
     * @param handlerMethod HandlerMethod，用于检查返回类型是否为JSON
     * @return boolean，如果请求的Content-Type包含JSON或处理方法的返回类型不是ModelAndView，则返回true
     */
    protected boolean isResponseJson(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) {
        // 检查请求内容类型是否为JSON
        if (response.getContentType() != null) {
            if (response.getContentType().equalsIgnoreCase("application/json")) {
                return true;
            }
        }
        if (handlerMethod != null) {
            // 获取处理方法的返回类型，并检查是否为ModelAndView的子类
            // Class<?> returnType = handlerMethod.getBeanType();
            // return !ModelAndView.class.isAssignableFrom(returnType);
        }
        return true;
    }


    /**
     * 打印日志
     */
    protected void printLog(HttpStatus status, String message, HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
        logger.error("URL=" + request.getRequestURI() + "------> Exception: " + message, exception);
        // logger.error("URL=" + request.getRequestURI() + "------> Exception: " + message);
    }
}
